#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

#include <linux/io.h>

#include "led_opr.h"


static int major = 0;
static struct class *led_class;
struct led_operations *p_led_opr;

//// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址：0x02290000 + 0x14
//static volatile int* IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
//// GPIO5_GDIR 地址：0x020AC004
//static volatile int* GPIO5_GDIR;
////GPIO5_DR 地址：0x020AC000
//static volatile int* GPIO5_DR;


#define MIN(a, b) (a < b ? a : b)

void led_class_create_device(int minor)
{
	device_create(led_class, NULL, MKDEV(major, minor), NULL, "my_led@%d", minor);
}

void led_class_destroy_device(int minor)
{
	device_destroy(led_class, MKDEV(major, minor));
}

void register_led_operations(struct led_operations *opr)
{
	p_led_opr = opr;
}

EXPORT_SYMBOL(led_class_create_device);
EXPORT_SYMBOL(led_class_destroy_device);
EXPORT_SYMBOL(register_led_operations);



static int led_open(struct inode *inode, struct file *file)
{
	int minor = iminor(inode); // 获取次设备号，具体机制我不清楚
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	p_led_opr->init(minor);
	
	return 0;
}

static ssize_t led_write(struct file *file, const char __user *in, size_t size, loff_t *off)
{
	unsigned long err;
	char status;
	struct inode *inode = file_inode(file); // 从file结构体中提取出它所关联的inode结构体指针
	int minor = iminor(inode); // 获取次设备号

	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_from_user(&status, in, 1);

    p_led_opr->ctl(minor, status);

	return 1; // 返回写入的字节数
}

static const struct file_operations led_fops = {
	.owner	 = THIS_MODULE,
	.open    = led_open,
	.write	 = led_write,
};

// 入口函数
static int __init led_init(void)
{
	printk("%s %s : %d\n", __FILE__, __FUNCTION__, __LINE__);

	major  = register_chrdev(0, "my_led", &led_fops);

//	// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址：0x02290000 + 0x14
//	IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000 + 0x14, 4);
//	// GPIO5_GDIR 地址：0x020AC004
//	GPIO5_GDIR = ioremap(0x020AC004, 4);
//	//GPIO5_DR 地址：0x020AC000
//	GPIO5_DR =  ioremap(0x020AC000, 4);

	led_class = class_create(THIS_MODULE, "my_led");
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "my_led");
	return 0;
}

// 出口函数
static void __exit led_exit(void)
{
	device_destroy(led_class, MKDEV(major, 0));
	class_destroy(led_class);

//	iounmap(GPIO5_DR);
//	iounmap(GPIO5_GDIR);
//	iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
/* 这里有一个问题：把点灯放到chip.c之后，谁来做iounmap的工作？ */
	unregister_chrdev(major, "my_led");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");




